<?php

namespace App\Libraries\Payment\DirectKylin;

use App\Exceptions\TransactionException;
use App\Libraries\Payment\PaymentInterface;
use App\Models\Setting;
use App\Services\Withdraw\UserWithdrawService;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use Illuminate\Support\Facades\Log;

class DirectKylinPayment implements PaymentInterface
{
    const TRANSFER_REQUEST_API = 'https://b.51bojun.com/change-batch/api/wechat/change/batch/single/transfer';

    public static function getMerchantInfo()
    {
        return [
            // MD5
            'md5' => config('services.payment.direct.md5'),
            // 商户号
            'merchantNo' => config('services.payment.direct.merchantNo'),
            // 微信商户号
            'subMerchantId' => config('services.payment.direct.subMerchantId'),
            'subAppId' => config('services.wechat.appid'),
        ];
    }

    /**
     * @param array $params
     * @return string
     * @throws TransactionException
     * @throws \App\Exceptions\WithdrawException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function makeRequest(array $params): string
    {
        $bank = Setting::get('bank');
        UserWithdrawService::checkAccountBank($params['transAmount']);

        if (env('PAYMENT_SANDBOX')) {
            return self::fakeRequest($params);
        }

        $merchantInfo = self::getMerchantInfo();
        $payload = [
            'sign' => '',
            'merchantNo' => $merchantInfo['merchantNo'],
            'subMerchantId' => $merchantInfo['subMerchantId'],
            'subAppId' => $merchantInfo['subAppId'],
            // ------------------------------------
            'outBizNo' => $params['outBizNo'],
            'transferAmount' => $params['transAmount'],
            'payeeOpenId' => $params['accountNo'],
            'transferRemark' => $params['remark'] . '_' . $bank['account_id'],
            'async' => 'true',
            'notifyUrl' => $params['notifyUrl'],
        ];

        $transferPayload = json_encode(array_merge($payload, [
            'sign' => self::md5sign($payload)
        ]), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

        $client = new Client();
        $headers = [
            'Content-type' => 'application/json',
        ];
        $request = new Request('POST', self::TRANSFER_REQUEST_API, $headers, $transferPayload);
        /** @var Response $result */
        $result = $client->send($request);
        $raw = $result->getBody()->getContents();

        Log::channel('kylin')->debug([
            'url' => self::TRANSFER_REQUEST_API,
            'post' => $transferPayload,
            'response' => $raw
        ]);

        $content = (array)json_decode($raw, true);
        if (empty($content)) {
            throw new TransactionException($raw);
        }
        if ($content['code'] == 500 || empty($content['data'])) {
            throw new TransactionException($content['msg'] ?? ($content['code'] ?? ''));
        }

        $orderId = $content['data']['accTransNo'] ?? 'EMPTY';
        if (empty($orderId)) {
            throw new TransactionException($content['msg'] ?? '转账异常');
        }

        return $orderId;
    }

    public static function fakeRequest(array $params): string
    {
        // $orderId = strtoupper(uniqid());
        $orderId = '20240618182540063401761548349142137854';
        Log::channel('sandbox')->debug([
            'orderId' => $orderId,
            'params' => $params,
        ]);

        return $orderId;
    }

    public static function md5sign($params = [])
    {
        unset($params['sign']);
        $md5key = self::getMerchantInfo()['md5'];

        ksort($params);
        $queryStrings = [];
        foreach ($params as $k => $v) {
            $queryStrings[] = sprintf("%s=%s", $k, $v);
        }
        $queryString = implode('&', $queryStrings);

        $stringToSign = $queryString . $md5key;

        return md5($stringToSign);
    }
}
